wayland: Implement DND icon hotspot API
authorJonas Ådahl <jadahl@gmail.com>
Tue, 8 Dec 2015 10:19:33 +0000 (18:19 +0800)
committerMatthias Clasen <mclasen@redhat.com>
Tue, 8 Dec 2015 16:47:07 +0000 (11:47 -0500)
In Wayland, the hotspot of a DND icon is set using the buffer offset in
wl_buffer.attach. To implement this, add a private API to cause the
next wl_surface.attach to offset the new buffer with a given offset.
Setting a DND icon hotspot sets this offset while also queuing a redraw
of the window to trigger the wl_surface.attach.

https://bugzilla.gnome.org/show_bug.cgi?id=759168

gdk/wayland/gdkdnd-wayland.c
gdk/wayland/gdkprivate-wayland.h
gdk/wayland/gdkwindow-wayland.c

index f20a0e7ab07a7b5b6927f704ddcec1fd95719fc6..0bb32793f1c7e365ea49dc1211ff0008c65eed72 100644 (file)
@@ -24,6 +24,7 @@
 #include "gdkproperty.h"
 #include "gdkprivate-wayland.h"
 #include "gdkdisplay-wayland.h"
+#include "gdkwaylandwindow.h"
 
 #include "gdkdeviceprivate.h"
 
@@ -48,6 +49,8 @@ struct _GdkWaylandDragContext
   uint32_t serial;
   gdouble x;
   gdouble y;
+  gint prev_hot_x;
+  gint prev_hot_y;
   gint hot_x;
   gint hot_y;
 };
@@ -306,8 +309,27 @@ gdk_wayland_drag_context_set_hotspot (GdkDragContext *context,
                                       gint            hot_x,
                                       gint            hot_y)
 {
-  GDK_WAYLAND_DRAG_CONTEXT (context)->hot_x = hot_x;
-  GDK_WAYLAND_DRAG_CONTEXT (context)->hot_y = hot_y;
+  GdkWaylandDragContext *context_wayland = GDK_WAYLAND_DRAG_CONTEXT (context);
+
+  context_wayland->prev_hot_x = context_wayland->hot_x;
+  context_wayland->prev_hot_y = context_wayland->hot_x;
+  context_wayland->hot_x = hot_x;
+  context_wayland->hot_y = hot_y;
+
+  if (context_wayland->prev_hot_x == hot_x &&
+      context_wayland->prev_hot_x == hot_x)
+    return;
+
+  _gdk_wayland_window_offset_next_wl_buffer (context_wayland->dnd_window,
+                                             -hot_x, -hot_y);
+  gdk_window_invalidate_rect (context_wayland->dnd_window,
+                              &(GdkRectangle) {
+                                .x = 0,
+                                .y = 0,
+                                .width = 1,
+                                .height = 1,
+                              },
+                              FALSE);
 }
 
 static void
index 00db37f3b18d91acff04267eea4b21572dbedfb5..c4b51856434e39809a52fefc833ad0abe19abebb 100644 (file)
@@ -104,6 +104,10 @@ void            _gdk_wayland_window_register_dnd (GdkWindow *window);
 GdkDragContext *_gdk_wayland_window_drag_begin (GdkWindow *window,
                                                GdkDevice *device,
                                                GList     *targets);
+void            _gdk_wayland_window_offset_next_wl_buffer (GdkWindow *window,
+                                                           int        x,
+                                                           int        y);
+
 GdkDragContext * _gdk_wayland_drop_context_new (struct wl_data_device *data_device);
 void _gdk_wayland_drag_context_set_source_window (GdkDragContext *context,
                                                   GdkWindow      *window);
index 60dfc59c9c8812daa296e286be2f5f18bd27f797..9a01d42ff761c68c13ba91bf0e1cc3bfc2be85c8 100644 (file)
@@ -121,6 +121,8 @@ struct _GdkWindowImplWayland
   GdkWindow *transient_for;
 
   cairo_surface_t *cairo_surface;
+  int pending_buffer_offset_x;
+  int pending_buffer_offset_y;
 
   gchar *title;
 
@@ -564,7 +566,10 @@ gdk_wayland_window_attach_image (GdkWindow *window)
   /* Attach this new buffer to the surface */
   wl_surface_attach (impl->surface,
                      _gdk_wayland_shm_surface_get_wl_buffer (impl->cairo_surface),
-                     0, 0);
+                     impl->pending_buffer_offset_x,
+                     impl->pending_buffer_offset_y);
+  impl->pending_buffer_offset_x = 0;
+  impl->pending_buffer_offset_y = 0;
 
   /* Only set the buffer scale if supported by the compositor */
   display = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
@@ -2564,6 +2569,32 @@ gdk_wayland_window_get_wl_surface (GdkWindow *window)
   return GDK_WINDOW_IMPL_WAYLAND (window->impl)->surface;
 }
 
+/**
+ * gdk_wayland_window_offset_next_wl_buffer:
+ * @window (type GdkWaylandWindow): a #GdkWindow
+ * @x: x offset which the next buffer should be attached at
+ * @y: y offset which the next buffer should be attached at
+ *
+ * Make GDK attach the next buffer at the given offset. This is useful for
+ * DND icons which may have a hotspot other than (0, 0).
+ *
+ * Since: 3.20
+ */
+void
+gdk_wayland_window_offset_next_wl_buffer (GdkWindow *window,
+                                          int        x,
+                                          int        y)
+{
+  GdkWindowImplWayland *impl;
+
+  g_return_if_fail (GDK_IS_WAYLAND_WINDOW (window));
+
+  impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
+
+  impl->pending_buffer_offset_x = x;
+  impl->pending_buffer_offset_y = y;
+}
+
 static struct wl_egl_window *
 gdk_wayland_window_get_wl_egl_window (GdkWindow *window)
 {